using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace WbsEditor
{
    public partial class TfsWorkItemForm : Form
    {
        public TfsWorkItemForm()
        {
            InitializeComponent();
        }

        private WorkBreakdownStructure _wbs;
        public WorkBreakdownStructure Wbs
        {
            get
            {
                return _wbs;
            }
            set
            {
                _wbs = value;
            }
        }

        private WorkBreakdownStructure _wbsCopy;

        private WbsTfsClient _tfsClient;
        public WbsTfsClient TfsClient
        {
            get
            {
                return _tfsClient;
            }
            set
            {
                _tfsClient = value;
            }
        }

        private WbsNodeBindingList _wbsNodeList = new WbsNodeBindingList();

        public new DialogResult ShowDialog()
        {
            if (null == TfsClient)
                return DialogResult.Cancel;
            if (null == Wbs)
                return DialogResult.Cancel;

            SetComboBoxDataSources();
            CreateBindingList();

            return base.ShowDialog();
        }

        private void SetComboBoxDataSources()
        {
            iterationDataGridViewComboBoxColumn.DataSource = TfsClient.GetTeamProjectIterations();
            string[] assignees = TfsClient.GetPossibleAssignedToNames();
            List<string> assigneeList = new List<string>();
            assigneeList.Add("");
            assigneeList.AddRange(assignees);
            assignedToDataGridViewComboBoxColumn.DataSource = assigneeList;
        }

        private void CreateBindingList()
        {
            _wbsCopy = Wbs.DeepClone(true);

            WbsTraverser.TraverseTree(_wbsCopy.Root,
                delegate(WbsNode node)
                {
                    if (node.IsLeaf && node.IsPublished)
                    {
                        node.Wbs = _wbsCopy;
                        _wbsNodeList.Add(node);
                    }
                });

            wbsNodeBindingListBindingSource.DataSource = _wbsNodeList;
        }

        private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            return;
        }

        private object _clipCellValue;
        private int _clipCellColumnIndex = -1;

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_wbsNodeDataGrid.SelectedCells.Count <= 0)
                return;

            DataGridViewCell cell = _wbsNodeDataGrid.SelectedCells[0];
            _clipCellValue = cell.Value;
            _clipCellColumnIndex = cell.ColumnIndex;
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (0 >= _clipCellColumnIndex)
                return;
            foreach (DataGridViewCell cell in _wbsNodeDataGrid.SelectedCells)
            {
                if (_clipCellColumnIndex != cell.ColumnIndex)
                    continue;
                if (cell.OwningColumn.DataPropertyName.Equals("State"))
                {
                    WbsNode node = (WbsNode) wbsNodeBindingListBindingSource.Current;
                    if (null == Array.Find<string>(node.PossibleNextStates, x => x.Equals(_clipCellValue)))
                        continue;
                }
                cell.Value = _clipCellValue;
            }
        }

        private void _publishButton_Click(object sender, EventArgs e)
        {
            PublishChangedWorkItems();

            DialogResult = DialogResult.OK;
            Close();
        }

        private void PublishChangedWorkItems()
        {
            foreach (WbsNode node in _wbsNodeList)
            {
                WbsNode originalNode = WbsTraverser.GetNodeWithWorkItemId(Wbs.Root, node.WorkItemId);
                if (null == originalNode)
                    continue;

                if (node.AssignedTo.Equals(originalNode.AssignedTo)
                    && node.State.Equals(originalNode.State)
                    && node.Title.Equals(originalNode.Title)
                    && node.Priority == originalNode.Priority
                    && node.Iteration == originalNode.Iteration
                    && (Math.Abs(node.RemainingWorkInDays - originalNode.RemainingWorkInDays) < 0.0005)
                    && (Math.Abs(node.CompletedWorkInDays - originalNode.CompletedWorkInDays) < 0.0005)
                    )
                    continue;

                TfsClient.PublishAllFieldsExceptDescription(Wbs, node);

                originalNode.AssignedTo = node.AssignedTo;
                originalNode.Title = node.Title;
                originalNode.State = node.State;
                originalNode.Priority = node.Priority;
                originalNode.RemainingWorkInDays = node.RemainingWorkInDays;
                originalNode.CompletedWorkInDays = node.CompletedWorkInDays;
            }
        }

        private void _cancelButton_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }

        private void _wbsNodeDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }
    }

    public class WbsNodeBindingList : BindingList<WbsNode>
    {
        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            List<WbsNode> tempList = (List<WbsNode>)Items;
            tempList.Sort(new PropertyComparer(prop, direction));
        }

        protected override bool SupportsSortingCore
        {
            get
            {
                return true;
            }
        }

        private bool _isSorted = false;
        protected override bool IsSortedCore
        {
            get
            {
                return _isSorted;
            }
        }

        protected override void RemoveSortCore()
        {
        }

        internal class PropertyComparer : System.Collections.Generic.IComparer<WbsNode>
        {
            internal PropertyComparer(PropertyDescriptor prop, ListSortDirection direction)
            {
                _prop = prop;
                _direction = direction;
                _compareFloats = _prop.Name.Contains("InDays") || _prop.Name.Contains("InDisplayUnits");
                _compareInts = _prop.Name.Equals("WorkItemId") || _prop.Name.Equals("Priority");
                _propertyInfo = typeof(WbsNode).GetProperty(_prop.Name);
            }

            private PropertyDescriptor _prop;
            private ListSortDirection _direction;
            private PropertyInfo _propertyInfo;
            private bool _compareFloats;
            private bool _compareInts;

            int System.Collections.Generic.IComparer<WbsNode>.Compare(WbsNode x, WbsNode y)
            {
                int returnValue = 0;
                if (_compareInts)
                {
                    int ix = GetIntValue(x);
                    int iy = GetIntValue(y);

                    if (ix < iy)
                        returnValue = -1;
                    else if (ix == iy)
                        returnValue = 0;
                    else
                        returnValue = 1;
                }
                else if (_compareFloats)
                {
                    float fx = GetFloatValue(x);
                    float fy = GetFloatValue(y);

                    if (fx < fy)
                        returnValue = -1;
                    else if (Math.Abs(fx - fy) < 0.0004)
                        returnValue = 0;
                    else 
                        returnValue = 1;
                }
                else
                {
                    string sx = GetStringValue(x);
                    string sy = GetStringValue(y);

                    returnValue = string.Compare(sx, sy);
                }

                if (_direction == ListSortDirection.Ascending)
                    return returnValue;
                else
                    return -returnValue;
            }

            private int GetIntValue(object x)
            {
                int i = (int)_propertyInfo.GetValue(x, new object[] { });
                return i;
            }

            private float GetFloatValue(object x)
            {
                float f = (float)_propertyInfo.GetValue(x, new object[] { });
                return f;
            }

            private string GetStringValue(object x)
            {
                string s = (string)_propertyInfo.GetValue(x, new object[] { });
                return s;
            }
        }
    }
}